using CfgTable;
using IQIGame.Onigao.Framework;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.GamePlay
{
    public class ItemData : IReusableClass
    {
        /*-- members --*/
        /// <summary>
        /// 唯一id
        /// </summary>
        public long id { get; protected set; }

        /// <summary>
        /// item配置id
        /// </summary>
        public int cid { get; protected set; }

        /// <summary>
        /// 数量
        /// </summary>
        public int num { get; protected set; } = 1;

        /// <summary>
        /// 已使用数量
        /// </summary>
        public int usedNum { get; protected set; }

        /// <summary>
        /// 创建时间（毫秒时间戳）
        /// </summary>
        public long createTime { get; protected set; }

        #region 配置 && 逻辑

        private CfgItem _cfgData = null;

        public CfgItem cfgData
        {
            get
            {
                if (this.cid > 0 && this._cfgData == null)
                {
                    this._cfgData = TableCenter.item.Get(this.cid);
                }

                return this._cfgData;
            }
        }

        public ItemData SetNum(int num)
        {
            this.num = num;
            return this;
        }

        public HeroData currWearer => GameDataCenter.PlayerData.hero.GetEquipWearer(this.id);

        #endregion

        public ItemData Sync(ItemPOD pod)
        {
            this.id = pod.id;
            this.cid = pod.cid;
            this.usedNum = pod.usedNum;
            this.createTime = pod.createTime;

            this.OnSync(pod);
            return this;
        }

        protected virtual void OnSync(ItemPOD pod)
        {
        }


        private void Clear()
        {
            this.OnClear();

            this.id = 0;
            this.cid = 0;
            this.num = 1;
            this.usedNum = 0;
            this.createTime = 0;
            this._cfgData = null;
        }

        protected virtual void OnClear()
        {
        }

        #region 对象池

        public virtual uint MaxStore => 50;

        public void OnReset()
        {
            this.Clear();
        }

        public void Put2Pool()
        {
            ClassPool.PutAutoType(this);
        }

        static public ItemData NewFromPool()
        {
            return ClassPool.Get<ItemData>();
        }
        #endregion

        static public ItemData ConvertFromPOD(ItemPOD pod)
        {
            if (pod.equipmentData != null)
            {
                return ItemEquipmentData.NewFromPool().Sync(pod);
            }
            else if (pod.portableData != null)
            {
                return ItemPortableData.NewFromPool().Sync(pod);
            }
            return NewFromPool().Sync(pod);
        }

        static public ItemData ConvertFromBasicItem(int cid, int num)
        {
            ItemData ret = NewFromPool();
            ret.id = cid;
            ret.cid = cid;
            ret.num = num;
            return ret;
        }
    }

    public class ItemEquipmentData : ItemData
    {
        /*-- members --*/
        /// <summary>
        ///  等级(从1开始)
        /// </summary>
        public int level { get; private set; } = 1;

        /// <summary>
        ///  经验
        /// </summary>
        public int exp { get; private set; }

        /// <summary>
        ///  锁定
        /// </summary>
        public bool isLock { get; private set; }

        /// <summary>
        ///  星级(从1开始)
        /// </summary>
        public int star { get; private set; } = 1;

        /// <summary>
        ///  皮肤Cid
        /// </summary>
        public int skinCid { get; private set; }

        #region 配置 && 逻辑

        private CfgEquipLevel _cfgLv = null;

        public CfgEquipLevel cfgLv
        {
            get
            {
                bool isChanged = (this.level >= 0 && this._cfgLv == null) ||
                                 (this._cfgLv != null && this._cfgLv.Level != this.level);
                if (isChanged)
                {
                    this._cfgLv = TableCenter.equipLevel.Get(this.level);
                }

                return this._cfgLv;
            }
        }

        public int maxLv
        {
            get
            {
                int max = this.level;
                int playLv = GameDataCenter.PlayerData.level;
                CfgItem cfgItem = this.cfgData;
                foreach (var cfgLv in TableCenter.equipLevel.DataList)
                {
                    if (max < cfgLv.Level && playLv >= cfgLv.PlayerLevel && cfgItem.Quality >= cfgLv.QualityLimit)
                    {
                        max = cfgLv.Level;
                    }
                }

                return max;
            }
        }

        public bool isMaxLv => this.level >= maxLv;

        private CfgEquipStar _cfgStar = null;

        public CfgEquipStar cfgStar
        {
            get
            {
                bool isChanged = (this.star >= 0 && this._cfgStar == null) ||
                                 (this._cfgStar != null && this._cfgStar.Star != this.star);
                if (isChanged)
                {
                    this._cfgStar = TableCenter.equipStar.GetCfg(this.cid, star);
                }

                return this._cfgStar;
            }
        }

        private int _maxStar = 0;

        public int maxStar
        {
            get
            {
                if (this._maxStar == 0)
                {
                    int max = this.star;
                    var cfg = TableCenter.equipStar.MaxCfg(this.cid);
                    if (cfg != null)
                        max = cfg.Star;

                    max = Math.Min(max, this.cfgData.StarLimit);
                    this._maxStar = Math.Max(1, max);
                }

                return this._maxStar;
            }
        }

        private CfgEquipSkin _cfgSkin = null;

        public CfgEquipSkin cfgSkin
        {
            get
            {
                bool isChanged = (this.skinCid > 0 && this._cfgSkin == null) ||
                                 (this.skinCid > 0 && this._cfgSkin != null && this._cfgSkin.Id != this.skinCid);
                if (isChanged)
                {
                    this._cfgSkin = TableCenter.equipSkin.Get(this.skinCid);
                }
                else if (this.skinCid == 0)
                {
                    this._cfgSkin = null;
                }

                return this._cfgSkin;
            }
        }

        public int skinCount
        {
            get { return TableCenter.equipSkin.CountList(this.cid); }
        }

        public CfgEquipSkin GetCfgEquipSkin(int index)
        {
            return TableCenter.equipSkin.GetCfg(this.cid, index);
        }

        #endregion

        protected override void OnSync(ItemPOD pod)
        {
            this.Sync(pod.equipmentData);
        }

        public ItemEquipmentData Sync(ItemEquipmentPOD pod)
        {
            this.exp = pod.exp;
            this.isLock = pod.isLock;
            this.level = pod.level;
            this.star = pod.star;
            this.skinCid = pod.skinCid;
            return this;
        }

        protected override void OnClear()
        {
            this.level = 1;
            this.exp = 0;
            this.isLock = false;
            this.star = 1;
            this.skinCid = 0;

            this._cfgLv = null;
            this._cfgStar = null;
            this._cfgSkin = null;
            this._maxStar = 0;
        }

        #region 对象池
        public override uint MaxStore => 30;

        static public new ItemEquipmentData NewFromPool()
        {
            return ClassPool.Get<ItemEquipmentData>();
        }
        #endregion
        static public ItemEquipmentData ConvertFromCidNum(int cid, int num)
        {
            ItemEquipmentData ret = NewFromPool();
            ret.cid = cid;
            ret.num = num;
            return ret;
        }
    }

    public class ItemPortableData : ItemData
    {
        public List<int> parts { get; private set; }

        public int level { get; private set; }

        protected override void OnSync(ItemPOD pod)
        {
            this.Sync(pod.portableData);
        }

        public ItemPortableData Sync(ItemPortablePOD pod)
        {
            level = pod.level;
            parts = pod.parts;
            return this;
        }

        protected override void OnClear()
        {
            level = 0;
            parts = null;
        }

        #region 对象池

        public override uint MaxStore => 30;

        static public new ItemPortableData NewFromPool()
        {
            return ClassPool.Get<ItemPortableData>();
        }

        #endregion
    }

    public class ItemShowData : IReusableClass
    {
        public int cid;
        public int num;
        public bool isNew;

        public CfgItem cfgData => TableCenter.item.Get(cid);

        public void OnReset()
        {
            cid = 0;
            num = 0;
            isNew = false;
        }

        #region 对象池

        public uint MaxStore => 50;

        public static ItemShowData NewFromPool()
        {
            return ClassPool.Get<ItemShowData>();
        }

        public void Put2Pool()
        {
            ClassPool<ItemShowData>.Put(this);
        }

        #endregion

        static public ItemShowData ConvertFromPOD(ItemShowPOD pod)
        {
            ItemShowData ret = NewFromPool();
            ret.cid = pod.cid;
            ret.num = pod.num;
            ret.isNew = pod.tag == NetProtocol.Enum.ItemTag.NEW;
            return ret;
        }
    }

    public class ItemModuleData
    {
        // basicItem 统一封装为 ItemData
        // public Dictionary<int, int> basicItems { get; private set; } // 所有可堆叠对象
        protected Dictionary<long, ItemData> dicSidItem { get; private set; }
        protected Dictionary<int, int> itemDebts { get; private set; } // 欠账
        protected Dictionary<int, int> itemCdInfo { get; private set; } // cid = lastUsedTime
        protected Dictionary<int, int> exchangeRecords { get; private set; } // 兑换记录，cid = count

        private Type warehouseExcludeType = typeof(ItemEquipmentData);

        public ItemModuleData(Dictionary<int, int> basicItems, Dictionary<int, int> itemDebts,
            Dictionary<int, int> itemCdInfo, Dictionary<int, int> exchangeRecords)
        {
            this.itemDebts = itemDebts;
            this.itemCdInfo = itemCdInfo;
            this.exchangeRecords = exchangeRecords;
            this.dicSidItem = new(32);

            foreach (var item in basicItems)
            {
                this.AddItem(ItemData.ConvertFromBasicItem(item.Key, item.Value));
            }
        }

        public void AddItem(ItemData itemData)
        {
            if (!this.IsContainsItem(itemData.id))
            {
                this.dicSidItem[itemData.id] = itemData;
            }
        }

        public bool IsContainsItem(long id)
        {
            return this.dicSidItem.ContainsKey(id);
        }

        public bool TryGetItem(long id, out ItemData item)
        {
            return this.dicSidItem.TryGetValue(id, out item);
        }

        public bool TryRemoveItem(long id, out ItemData item)
        {
            this.dicSidItem.TryGetValue(id, out item);
            return this.dicSidItem.Remove(id);
        }

        public List<ItemData> GetList(System.Func<ItemData, bool> fitlerAdd = null)
        {
            List<ItemData> list = new(16);
            foreach (var item in this.dicSidItem.Values)
            {
                if (fitlerAdd == null || fitlerAdd(item))
                {
                    list.Add(item);
                }
            }
            return list;
        }

        public List<ItemData> GetItemList(System.Func<ItemData, bool> fitlerAdd = null)
        {
            System.Func<ItemData, bool> _filter = item =>
            {
                if (item.GetType() != warehouseExcludeType)
                    return (fitlerAdd == null) || fitlerAdd(item);
                return false;
            };
            return GetList(_filter);
        }

        public List<ItemData> GetSortItemList(System.Func<ItemData, bool> fitlerAdd, Comparison<ItemData> sortFunc)
        {
            var result = this.GetItemList(fitlerAdd);
            if (result.Count > 1 && sortFunc != null)
            {
                result.Sort(sortFunc);
            }
            return result;
        }

        public List<ItemEquipmentData> GetEquipList(System.Func<ItemEquipmentData, bool> filter = null)
        {
            System.Func<ItemData, bool> _filter = item =>
            {
                if (item is ItemEquipmentData itemEquip)
                    return (filter == null) || filter(itemEquip);
                return false;
            };

            var list = GetList(_filter);

            List<ItemEquipmentData> result = new(list.Count);
            foreach (var item in list)
            {
                result.Add((ItemEquipmentData)item);
            }
            return result;
        }

        public void UpItemCdInfo(Dictionary<int, int> itemCdInfo)
        {
            if (itemCdInfo == null || itemCdInfo.Count == 0)
                return;

            var _dic = this.itemCdInfo;
            foreach (var item in itemCdInfo)
            {
                _dic[item.Key] = item.Value;
            }
        }

        public void UpItemDebts(Dictionary<int, int> itemDebts)
        {
            if (itemDebts == null || itemDebts.Count == 0)
                return;

            var _dic = this.itemDebts;
            foreach (var item in itemDebts)
            {
                _dic[item.Key] = item.Value;
            }
        }

        public void Clear()
        {
            foreach (var item in this.dicSidItem.Values)
            {
                item.Put2Pool();
            }

            this.itemCdInfo.Clear();
            this.itemDebts.Clear();
            this.exchangeRecords.Clear();
            this.dicSidItem.Clear();
        }
    }
}
